/**
 * @description 上传图片
 */
import React from 'react';
import classnames from "classnames";
import "./styles/App.less";
import lrz from "lrz";
import { Icon } from "wd-mobile";

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      imgs: []
    };

    // 图片压缩尺寸
    this.compressSize = 200;
    // 图片数量
    this.imgAmount = this.props.imgs.length;
    // 最大上传限制
    this.maxFileSize = 10 * 1048576;
    // 最大压缩限制，大于这个的都要压缩
    this.maxCompressSize = 0.5 * 1048576;
    // 选择文件
    this.fileChose = this.fileChose.bind(this);
    // input
    this.inputRef = React.createRef();
  }

  componentDidMount() {
    this.initImgListData(this.props.imgs)
  }

  render() {
    return (
      <div className="x-uploadImage">
        {
          this.state.imgs.map((item, index) => {
            return (
              <div key={index} className={`x-uploadImage-item x-uploadImage-${item.type} x-flex-rownum-${this.props.rowNum}`}
                style={{ backgroundImage: `url(${item.showUrl})` }}
              >
                {
                  item.type == "img" && <Icon className="x-icon-close-circle" onClick={() => {
                    const imgItems = [...this.imgItemList];// 获取已存在图片数组
                    imgItems.splice(index, 1);// 删除指定索引图片
                    this.imgAmount--;// 图片数量-1
                    this.setImgList(imgItems);
                    const imgListUrl = imgItems.map(item => {
                      return item.realUrl || item.showUrl;
                    });
                    // 删除图片回调
                    this.props.onChange && this.props.onChange(imgListUrl);
                  }} />
                }
                {
                  item.type == "add" && <input ref={this.inputRef} type="file" accept="image/*" multiple className="x-uploadImage-input" onChange={this.fileChose} />
                }
              </div>
            )
          })
        }
      </div>
    );
  }

  // 初始化图片列表数据
  initImgListData(imgs) {
    let imgItemList = [];
    if (!!imgs && Array.isArray(imgs)) {
      imgItemList = imgs.map(imgUrl => {
        return { showUrl: imgUrl, type: "img" }
      })
    }
    this.setImgList(imgItemList);
  }

  // 设置图片数据
  setImgList(imgItemList) {
    // 需要设置到state内的图片类元素数量
    const imgState = [];
    // 是否需要添加按钮
    const needAdd = this.props.max == 0 || this.props.max > imgItemList.length;
    // 最后一行元素数量
    const remainder = (imgItemList.length + (needAdd ? 1 : 0)) % this.props.rowNum;
    // 空元素数量，空元素是为了在flex下更好的实现排版的占位元素，实现即可换行又可均分
    const emptyNum = remainder == 0 ? 0 : this.props.rowNum - remainder;
    // 元素总量
    const totalNum = imgItemList.length + emptyNum + (needAdd ? 1 : 0);
    // 循环生成所有元素数组
    for (let i = 0; i < totalNum; i++) {
      if (!!imgItemList[i]) {
        imgState.push(imgItemList[i]);
      } else if (!imgItemList[i] && i == imgItemList.length && needAdd) {
        // 如果没达到最大限制，可以继续添加
        imgState.push({ showUrl: "", type: "add" })
      } else {
        imgState.push({ showUrl: "", type: "empty" })
      }
    }
    this.imgItemList = imgItemList;
    this.setState({
      imgs: imgState
    })
  }

  // 选择文件
  fileChose(e) {
    let filesLength = e.target.files.length;
    // 计算本次上传图片数量
    let limitMax = this.props.max <= 0 || this.props.max >= filesLength ? filesLength : this.props.max;

    // 遍历图片
    for (let i = 0; i < limitMax; i++) {
      const file = e.target.files[i];

      // 检查图片是否超过最大限制
      if (file.size > this.maxFileSize) {
        alert(`${file.name}，文件过大，请上传小于${this.maxFileSize}M的图片`);
        return false;
      }

      // 修复图片显示兼容
      this.fixCompatible(file);
    }
  }

  // 修复图片显示兼容
  fixCompatible(file) {
    lrz(file)
      .then((rst) => {
        this.img = rst.base64;
        this.inputRef.current.value = null;

        // 检查图片是否大于最小压缩限制
        if (file.size > this.maxCompressSize) {
          this.compressImg(rst.base64);
        } else {
          this.uploadImages(rst.base64);
        }
      })
      .catch(function (err) {
        this.props.onError && this.props.onError(err);
      });
  }

  // canvas压缩图片
  compressImg(url) {
    var img = new Image();
    img.src = url;
    var base64Str = "";
    img.onload = () => {
      // canvas压缩处理
      let xm = parseInt(img.width / this.compressSize);
      let imgW = img.width / xm;
      let imgH = img.height / xm;
      let clipCanvas = document.createElement("canvas");
      clipCanvas.width = imgW;
      clipCanvas.height = imgH;
      let clipCtx = clipCanvas.getContext("2d");
      clipCtx.drawImage(img, 0, 0, imgW, imgH);
      base64Str = clipCanvas.toDataURL('image/png');

      // 转成流上传
      this.uploadImages(base64Str);
    }
  }

  // base64转blob
  dataURLtoBlob(dataurl) { // dataurl转blob
    const arr = dataurl.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    let n = bstr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {
      type: mime
    });
  }

  // 上传图片
  uploadImages(imagesBase64) {
    const inputName = 'file';
    const apiUrl = this.props.uploadUrl; // 接口地址

    // 设置图片数据列表
    const imgItems = [...this.imgItemList];// 获取已存在图片数组
    imgItems.push({ showUrl: imagesBase64, type: "img"}); // 增加图片
    this.imgAmount++;// 图片数量+1
    this.setImgList(imgItems);

    // 当前图片索引
    const thisItemIndex = imgItems.length - 1;

    // 请求
    const ajax = (url, data, success) => { // ajax
      const xhr = new XMLHttpRequest();
      xhr.withCredentials = true;
      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
          xhr.onreadystatechange = null;
          if (xhr.status === 200) {
            success(xhr.responseText);
          }
        }
      }
      xhr.open('POST', url, true);
      xhr.send(data);
    }

    // 转formdata
    const setFormData = blob => {
      const formData = new FormData();
      formData.append(inputName, blob, `${(new Date().getTime())}.${blob.type.split('/')[1]}`);
      return formData;
    }

    // 发送请求
    ajax(apiUrl, setFormData(this.dataURLtoBlob(imagesBase64)), response => {
      const imgItems = [...this.imgItemList];// 获取已存在图片数组
      imgItems[thisItemIndex].realUrl = JSON.parse(response).data[0];// 设置上传后的地址
      this.setImgList(imgItems);
      const imgListUrl = imgItems.map(item => {
        return item.realUrl || item.showUrl;
      })
      // 完成上传回调
      this.props.onChange && this.props.onChange(imgListUrl);
    })
  }
}

App.defaultProps = {
  max: 0, // 最大图片数，0为不限制
  imgs: [], // 图片数组
  rowNum: 3, // 一行的图片数, 1-
  uploadUrl: "", // 上传接口
  onChange: null // 内容改变完成钩子
};

export default App;
